﻿#include "protreewidget.h"
#include <QDir>
#include "protreeitem.h"
#include "const.h"
#include <QHeaderView>
#include <QGuiApplication>
#include <QMenu>
#include <QIcon>
#include <QFileDialog>
#include <QDebug>
#include "removeprodialog.h"
#include "slideshowdialog.h"
ProTreeWidget::ProTreeWidget(QWidget *parent):QTreeWidget(parent),_active_item(nullptr),
    _right_btn_item(nullptr),_dialog_progress(nullptr),_selected_item(nullptr),
    _thread_create_pro(nullptr),_thread_open_pro(nullptr),_open_progressdlg(nullptr)
{
    this->header()->hide();

    //在生成的ProTreeWidget的项目root_item中点击右键，弹出菜单
    connect(this,&ProTreeWidget::itemPressed,this,&ProTreeWidget::SlotItemPressed);
    _action_import = new QAction(QIcon(":/icon/import.png"),tr(u8"导入文件"),this);
    _action_setstart = new QAction(QIcon(":/icon/core.png"),tr(u8"设置活动项目"),this);
    _action_closepro = new QAction(QIcon(":/icon/close.png"),tr(u8"关闭项目"),this);
    _action_slideshow = new QAction(QIcon(":/icon/slideshow.png"),tr(u8"轮播播放"),this);

    //触发导入文件
    connect(_action_import,&QAction::triggered,this,&ProTreeWidget::SlotImport);
    //触发设置活动项目
    connect(_action_setstart,&QAction::triggered,this,&ProTreeWidget::SlotSetActive);
    //触发关闭项目
    connect(_action_closepro,&QAction::triggered,this,&ProTreeWidget::SlotClosePro);
    //双击项目展示图片
    connect(this,&ProTreeWidget::itemDoubleClicked,this,&ProTreeWidget::SlotDoubleClickItem);
    //触发轮播播放
    connect(_action_slideshow,&QAction::triggered,this,&ProTreeWidget::SlotSlidShow);

    //设置背景音乐
    _player = new QMediaPlayer(this);
    _playlist = new QMediaPlaylist(this);
    _playlist->setPlaybackMode(QMediaPlaylist::Loop);
    _player->setPlaylist(_playlist);
}

//将目录添加到目录树中，AddProToTree函数里判断路径和名字是否准确，然后创建一个item插入到treewidget里。
void ProTreeWidget::AddProToTree(const QString &name, const QString &path)
{
    QDir dir(path);
    QString file_path = dir.absoluteFilePath(name);

    //检测重名，判断路径和名字都一样则拒绝加入
    if(_set_path.find(file_path) != _set_path.end())
    {
        return ;
    }

    //构建项目用的文件夹
    QDir pro_dir(file_path);
    if(!pro_dir.exists())
    {
        //创建文件夹
        bool enable = pro_dir.mkpath(file_path);
        if(!enable)
        {
            return ;
        }
    }

    _set_path.insert(file_path);

    //设置文件夹样式
    auto *item = new ProTreeItem(this,name,file_path,TreeItemPro);
    item->setData(0,Qt::DisplayRole,name);
    item->setData(0,Qt::DecorationRole,QIcon(":/icon/dir.png"));
    item->setData(0,Qt::ToolTipRole,file_path);

    this->addTopLevelItem(item);

}

//在SlotItemPressed函数中判断是否为右键点击，如果是再根据item的类型判断是root节点，则在菜单中添加动作。
void ProTreeWidget::SlotItemPressed(QTreeWidgetItem *pressedItem, int column)
{
    qDebug() << "SlotItemPressed\n";
    //如果是右键，则弹出菜单
    if(QGuiApplication::mouseButtons() == Qt::RightButton)
    {
        QMenu menu(this);
        int itemType = pressedItem->type();

        if(itemType == TreeItemPro)
        {
            _right_btn_item = pressedItem;
            menu.addAction(_action_import);
            menu.addAction(_action_setstart);
            menu.addAction(_action_closepro);
            menu.addAction(_action_slideshow);
            menu.exec(QCursor::pos());
        }
    }
}

//因为导入操作是一个耗时的操作，所以要放到单独的线程中执行，主线程启动一个进度对话框显示导入进度，同时可以控制导入的中止操作等。
//在导入时弹出一个文件选择对话框，设置默认路径
void ProTreeWidget::SlotImport()
{
    QFileDialog file_dialog;
    file_dialog.setFileMode(QFileDialog::Directory);
    file_dialog.setWindowTitle(tr(u8"选择导入的文件夹"));
    QString path = "";
    if(!_right_btn_item)
    {
        qDebug() << "_right_btn_item is empty\n";
        return;
    }

    path = dynamic_cast<ProTreeItem*>(_right_btn_item)->GetPath();
    file_dialog.setDirectory(path);
    file_dialog.setViewMode(QFileDialog::Detail);

    QStringList fileNames;
    if(file_dialog.exec())
    {
        fileNames = file_dialog.selectedFiles();
        if(fileNames.length() <= 0)
        {
            return;
        }
    }

    QString import_path = fileNames.at(0);
    int file_count = 0;

    //创建模态对话框
    _dialog_progress = new QProgressDialog(this);

    //线程传递参数是右值，所以要加引用std::ref()
    _thread_create_pro = std::make_shared<ProTreeThread>(std::ref(import_path),std::ref(path),
                                                         _right_btn_item,file_count,
                                                         this,_right_btn_item,nullptr);

    connect(_thread_create_pro.get(),&ProTreeThread::SigUpdateProgress,
            this,&ProTreeWidget::SlotUpdateProgress);
    connect(_thread_create_pro.get(),&ProTreeThread::SigFinishProgress,
            this,&ProTreeWidget::SlotFinishProgress);
    connect(_dialog_progress,&QProgressDialog::canceled,
            this,&ProTreeWidget::SlotCancelProgress);

    connect(this,&ProTreeWidget::SigCancelProgress,
            _thread_create_pro.get(),&ProTreeThread::SlotCancelProgress);

    _thread_create_pro->start();
    //初始化
    _dialog_progress->setWindowTitle("Please wait...");
    _dialog_progress->setFixedWidth(PROGRESS_WIDTH);
    _dialog_progress->setRange(0,PROGRESS_WIDTH);
    _dialog_progress->exec();

}

void ProTreeWidget::SlotSetActive()
{
    if(!_right_btn_item)
    {
        return;
    }

    QFont nullFont;
    nullFont.setBold(false);

    if(_active_item)
    {
        _active_item->setFont(0,nullFont);
    }

    _active_item = _right_btn_item;
    nullFont.setBold(true);
    _active_item->setFont(0,nullFont);
}

//实现关闭项目操作
void ProTreeWidget::SlotClosePro()
{
    //添加一个删除的对话框
    RemoveProDialog remove_pro_dialog;
    auto res = remove_pro_dialog.exec();
    if(res != QDialog::Accepted)
    {
        return;
    }

    bool b_remove = remove_pro_dialog.isRemove();
    auto index_right_btn = this->indexOfTopLevelItem(_right_btn_item);
    auto * protreeitem = dynamic_cast<ProTreeItem*>(_right_btn_item);
    auto * selecteditem = dynamic_cast<ProTreeItem*>(_selected_item);
    auto delete_path = protreeitem->GetPath();
    _set_path.remove(delete_path);

    if(b_remove)
    {
        QDir delete_dir(delete_path);
        delete_dir.removeRecursively();
    }

    if(protreeitem == _active_item)
    {
        _active_item = nullptr;
    }

    //
    if(selecteditem && protreeitem == selecteditem->GetRoot())
    {
        selecteditem = nullptr;
        _selected_item = nullptr;
        emit SigClearSelected();
    }

    delete this->takeTopLevelItem(index_right_btn);
    _right_btn_item = nullptr;
}

void ProTreeWidget::SlotUpdateProgress(int count)
{
    if(!_dialog_progress)
    {
        return;
    }

    if(count >= PROGRESS_MAX)
    {
        _dialog_progress->setValue(count%PROGRESS_MAX);
    }else
    {
        _dialog_progress->setValue(count);
    }
}

void ProTreeWidget::SlotFinishProgress()
{
    _dialog_progress->setValue(PROGRESS_MAX);
    _dialog_progress->deleteLater();
}

void ProTreeWidget::SlotCancelProgress()
{
    emit SigCancelProgress();
    delete _dialog_progress;
    _dialog_progress = nullptr;
}

void ProTreeWidget::SlotUpOpenProgress(int count)
{
    if(!_open_progressdlg)
    {
        return;
    }

    if(count >= PROGRESS_MAX)
    {
        _open_progressdlg->setValue(count%PROGRESS_MAX);
    }else
    {
        _open_progressdlg->setValue(count);
    }
}

void ProTreeWidget::SlotFinishOpenProgress()
{
    if(!_open_progressdlg)
    {
        return;
    }

    _open_progressdlg->setValue(PROGRESS_MAX);
    delete _open_progressdlg;
    _open_progressdlg = nullptr;
}

void ProTreeWidget::SlotCancelOpenProgress()
{
    emit SigCancelOpenProgress();
    delete _open_progressdlg;
    _open_progressdlg = nullptr;
}

void ProTreeWidget::SlotOPenPro(const QString &path)
{
    //如果仔目录树中存在，则返回
    if(_set_path.find(path) != _set_path.end())
    {
        return;
    }

    _set_path.insert(path);
    int file_count = 0;
    QDir pro_dir(path);
    QString proname = pro_dir.dirName();

    _thread_open_pro = std::make_shared<OpenTreeThread>(path,file_count,this,nullptr);

    _open_progressdlg = new QProgressDialog(this);

    connect(_thread_open_pro.get(),&OpenTreeThread::SigUpdateProgress,
            this,&ProTreeWidget::SlotUpOpenProgress);
    connect(_thread_open_pro.get(),&OpenTreeThread::SigFinishProgress,
            this,&ProTreeWidget::SlotFinishOpenProgress);

    connect(_open_progressdlg,&QProgressDialog::canceled,
            this,&ProTreeWidget::SlotCancelProgress);

    connect(this,&ProTreeWidget::SigCancelOpenProgress,
            _thread_open_pro.get(),&OpenTreeThread::SlotCancelProgress);

    _thread_open_pro->start();

    //初始化
    _open_progressdlg->setWindowTitle("Please wait...");
    _open_progressdlg->setFixedWidth(PROGRESS_WIDTH);
    _open_progressdlg->setRange(0,PROGRESS_WIDTH);
    _open_progressdlg->exec();

}

void ProTreeWidget::SlotNextShow()
{
    if(!_selected_item)
    {
        return;
    }

    auto *curItem = dynamic_cast<ProTreeItem*>(_selected_item)->GetNextItem();
    if(!curItem)
    {
        return;
    }

    emit SigUpdatePic(curItem->GetPath());
    _selected_item = curItem;
    this->setCurrentItem(curItem);
}

void ProTreeWidget::SlotPreShow()
{
    if(!_selected_item)
    {
        return;
    }

    auto *curItem = dynamic_cast<ProTreeItem*>(_selected_item)->GetPreItem();
    if(!curItem)
    {
        return;
    }

    emit SigUpdatePic(curItem->GetPath());
    _selected_item = curItem;
    this->setCurrentItem(curItem);

}

void ProTreeWidget::SlotSetMusic()
{
    QFileDialog file_dialog;
    file_dialog.setFileMode(QFileDialog::ExistingFiles);
    file_dialog.setWindowTitle(tr(u8"选择音频文件"));
    file_dialog.setDirectory(QDir::currentPath());
    file_dialog.setViewMode(QFileDialog::Detail);
    file_dialog.setNameFilter("(*.mp3)");
    QStringList fileNames;
    if(file_dialog.exec())
    {
        fileNames = file_dialog.selectedFiles();
    }else
    {
        return;
    }

    if(fileNames.length() <= 0) return;

    _playlist->clear();
    for(auto filename : fileNames)
    {
        _playlist->addMedia(QUrl::fromLocalFile(filename));
    }

    if(_player->state() != QMediaPlayer::PlayingState)
    {
        _playlist->setCurrentIndex(0);
    }
}

void ProTreeWidget::SlotStartMusic()
{
    _player->play();
}

void ProTreeWidget::SlotStopMusic()
{
    _player->stop();
}

//实现双击逻辑,判断为鼠标左键，就用一个成员变量_selected_item缓存双击的item，
//然后发送SigUpdateSelected信号通知右侧区域刷新显示。
void ProTreeWidget::SlotDoubleClickItem(QTreeWidgetItem *doubleItem, int column)
{
    if(QGuiApplication::mouseButtons() == Qt::LeftButton)
    {
        auto * tree_doubleItem = dynamic_cast<ProTreeItem*>(doubleItem);
        if(!tree_doubleItem) return;

        int itemtype = tree_doubleItem->type();
        if(itemtype == TreeItemPic)
        {
            emit SigUpdateSelected(tree_doubleItem->GetPath());
            _selected_item = doubleItem;
        }
    }
}


//实现槽函数SlotSlideShow,n内部创建一个SlideShowDlg智能指针对象，然后设置为模态对话框，并且最大化显示。
void ProTreeWidget::SlotSlidShow()
{
    qDebug() << u8"进入轮播图播放了\n";
    if(!_right_btn_item) return;

    auto * right_pro_item = dynamic_cast<ProTreeItem*>(_right_btn_item);

    //获取最后一个节点
    auto * last_child_item = right_pro_item->GetLastPicChild();
    if(!last_child_item) return;
    qDebug()<< "last child item name is " << last_child_item->GetPath()<< endl;

    //获取第一个节点
    auto * first_child_item = right_pro_item->GetFirstPicChild();
    if(!first_child_item) return;
    qDebug()<< "first child item name is " << first_child_item->GetPath()<< endl;

    //模态对话框
    _slide_show_dlg = std::make_shared<SlideShowDialog>(this,first_child_item,last_child_item);
    _slide_show_dlg->setModal(true);
    //最大化显示
    _slide_show_dlg->showMaximized();

}













